#pragma once

#include <cassert>
#include <stdint.h>
#include <vector>
#include "vector3.h"

namespace raytrace {

class Primitive;
class Ray;

class Scene {
 public:
  enum Mode {
    MODE_WHITTED,
    MODE_REVERSE_PATH,
    MODE_DEBUG_NORMAL,
    MODE_DEBUG_PATH_COUNT,// TODO
    MODE_DEBUG_VARIANCE   // TODO
  };

  Scene();
  ~Scene();

  void Clear();

  void DumpToLog() const;

  void AddPrimitive(Primitive* prim);

  Vector3 Trace(const Ray& r) const;

  Mode mode() const { return mode_; }
  void set_mode(Mode mode) {
    assert(mode == MODE_WHITTED || mode == MODE_REVERSE_PATH ||
           mode == MODE_DEBUG_NORMAL || mode == MODE_DEBUG_PATH_COUNT);
    mode_ = mode;
  }
  void set_num_light_samples(uint32_t num_light_samples) {
    num_light_samples_ = num_light_samples;
  }

 private:
  typedef std::vector<Primitive*> PrimitiveList;
  
  Vector3 TraceRay(const Ray& r, uint32_t depth) const;
  Vector3 TracePath(const Ray& r, uint32_t depth) const;

  PrimitiveList::const_iterator Intersect(const Ray& r,
                                          float& intersect_d) const;

  Mode mode_;
  uint32_t num_light_samples_;
  PrimitiveList primitives_;
  PrimitiveList lights_;
};

} // end namespace
